feat(models): surface the API's agency-filter diagnostics on PaginatedResponse - #55
Open
makegov-mark[bot] wants to merge 1 commit into
Open
feat(models): surface the API's agency-filter diagnostics on PaginatedResponse#55makegov-mark[bot] wants to merge 1 commit into
makegov-mark[bot] wants to merge 1 commit into
Conversation
…dResponse Agency values resolve fuzzily. A token can match nothing and be dropped, or match an organization the caller never intended and quietly scope the query to that subtree. Both look identical to "no such records exist" from the client side. The API reports both in a response-level `meta` block, but the SDK built `PaginatedResponse` key-by-key — `count`, `next`, `previous`, `results` — so `meta` was read by nobody and discarded. SDK users were the one group that could not see the diagnostics at all. `PaginatedResponse.meta` now carries it, populated at all 48 construction sites, with three accessors over the raw dict: - `unresolved_agency_tokens` — tokens that matched nothing, keyed by filter, for failing loudly in a pipeline. - `resolved_agencies` — the organization each token *did* match. This is the one that catches the wrong-organization case: nothing is dropped there, so an unresolved-token check cannot detect it. Comparing the resolved `name` is the only client-side signal. - `agency_warnings` — the API's human-readable notes. All three return empty rather than raising when `meta` is absent (most responses) or malformed, since `meta` is server-controlled and a shape change must not break a caller's loop. Also documents `page_metadata` as always `None`: the API has never emitted a `page_metadata` key, so the field has only ever read something that does not exist. Retained so existing attribute access keeps working. No change was needed for the 400 path — a fully-unresolvable agency filter already raises `TangoValidationError` via the existing `error`-key handler — but it is new behavior for `list_subawards()`, `list_opportunities()`, `list_notices()` and `list_vehicles()`, which previously returned an empty page. Covered by a test so the contract is pinned. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
PaginatedResponsegainsmeta, carrying the response-level metadata the API returns, plus three accessors over it.Agency filter values resolve fuzzily. Two things can go wrong, and until now neither was visible to an SDK user:
Both are indistinguishable from "no such records exist". The API reports both in a
metablock, but the SDK builtPaginatedResponsekey-by-key (count,next,previous,results), sometawas read by nobody and discarded. SDK users were the one group that could not see the diagnostics at all.API
resolved_agenciesis the one worth understanding. It is not a nicer spelling of the dropped-token check — it is the only client-side signal for case 2 above, where nothing is dropped and the only tell is that the resolvednameis not the organization you meant.Notes
PaginatedResponseconstruction sites, so it is uniform rather than available on whichever methods happened to get it.metais absent (the common case) or malformed.metais server-controlled; a shape change on the API side must not break a caller's loop. Covered by a test.page_metadatais documented as alwaysNone. The API has never emitted apage_metadatakey, so the field has only ever read something that does not exist. Retained rather than removed, since deleting an attribute breaks anyone referencing it — worth a separate deprecation decision.TangoValidationErrorthrough the existingerror-key handler. It is new behavior forlist_subawards(),list_opportunities(),list_notices()andlist_vehicles(), which previously returned an empty page, so there is now a test pinning it.Testing
345 pass, mypy clean, no new ruff findings (the 20 in the repo are pre-existing and none are on lines this touches). Seven new tests cover:
metapassthrough, dropped tokens across multiple filters, the wrong-organization case, warnings, absentmeta, malformedmeta, and the 400.